home *** CD-ROM | disk | FTP | other *** search
/ Pascal Super Library / Pascal Super Library (CW International)(1997).bin / REFERENC / TPR / TPR3B.TXT < prev    next >
Text File  |  1992-10-19  |  63KB  |  1,625 lines

  1.                    Chapter 3
  2.                  - continued -
  3.                  - Part 2 of 3 parts -
  4.                                     of the
  5.                             Turbo Pascal Reference
  6.  
  7.                            The Turbo Pascal Language
  8.  
  9.  
  10. This chapter is part of the Turbo Pascal Reference electronic freeware book (C)
  11. Copyright 1992 by Ed Mitchell.  This freeware book contains supplementary
  12. material to Borland Pascal Developer's Guide, published by Que Corporation,
  13. 1992.  However, Que Corporation has no affiliation with nor responsibility for
  14. the content of this free book.  Please see Chapter 1 of the Turbo Pascal
  15. Reference for important information about your right to distribute and use this
  16. material freely.  If you find this material of use, I would appreciate your
  17. purchase of one my books, such as the Borland Pascal Developer's Guide or
  18. Secrets of the Borland C++ Masters, Sams Books, 1992.  Thank you.
  19.  
  20.  
  21. Pointers and Complex Data Structures
  22.      Turbo Pascal provides a large variety of built-in data types.  However, to
  23. create specific data structures such as list, queues, stacks, trees and so on,
  24. requires that you create and maintain the appropriate data structures yourself.
  25. Pointers are used extensively to create these types of data structures.
  26.      Figure 3.4 illustrates a list structure containing a list of filenames. 
  27. Each filename is stored in a record, together with pointers to the next and
  28. previous items in the list. 
  29.  
  30. ***03tpr04.pcx***
  31. Figure 3.4.  Pointers are often used in record structures to create list data
  32. structures, as shown here.  In a list, each element is linked, via a pointer,
  33. to another element in the list.
  34.  
  35.      Such a list structure is represented as a Pascal record, containing space
  36. for the filename and other information, plus pointer values to the next and
  37. previous list entries.  Listing 3.6 shows a sample data record declared as the
  38. type TListEntry.  A pointer to TListEntry is defined as PListEntry.
  39.  
  40.  
  41. Listing 3.6.  A sample data record set up for use in a list data structure. 
  42. Note the use of the separate PListEntry, defined as a pointer to TListEntry.
  43.  
  44. type
  45.      { Data record to create the list structure }
  46.      PListEntry = ^TListEntry;
  47.      TListEntry = record
  48.        DirInfo : SearchRec;
  49.        Next    : PListEntry;
  50.        Previous: PListEntry;
  51.      end; {TListEntry}
  52.  
  53. A list is constructed out of these records by creating a pointer to the first
  54. item in the list, and storing the first pointer in a variable called ListHead,
  55. and using New ( PListEntry ) to create each entry.   The variable ListTail
  56. points to the last item in the list.
  57.  
  58.      var
  59.        ListHead : PListEntry;
  60.        ListTail : PListEntry;
  61.  
  62.      The Next field of the TListEntry record is used to point to the next
  63. succeeding item in the list.  Each time an item is added to the list, the
  64. previous item's Next field is set to point to the new item, and the new item's
  65. Next field, if its the last item in the list, is set to nil to mark the end of
  66. the list.
  67.      The Previous field is used to link the list of items in both directions. 
  68. In this way, the items in the list can be accessed in both the forward and the
  69. backwards directions.
  70.      Listing 3.7 presents a complete sample list program that reads the names
  71. of the files from the current subdirectory and places them into a list data
  72. structure.  The program then displays the list in both the forward and backward
  73. directions, using the Next or Previous pointer to reach the next or previous
  74. element in the list structure.
  75.  
  76. Listing 3.7.  This program uses pointers to create and manipulate a list data
  77. structure.  
  78.    1  program DemoList;
  79.    2  {
  80.    3  Demonstrates the use of pointers to create a list structure, demonstrates
  81. how
  82.    4  list traversal is done in both forwards and backwards directions, and
  83. provides
  84.    5  routines to add (or insert) and delete items in the list.
  85.    6  
  86.    7  You can modify these routines for use as a general purpose list
  87. manipulation
  88.    8  tool, by changing the ListEntry data structure to hold other types of
  89. data.
  90.    9  
  91.   10  This demonstration program uses the Dos library routines FindFirst and
  92.   11  FindNext to read the default file subdirectory.
  93.   12  }
  94.   13  uses  Dos;
  95.   14  
  96.   15  type
  97.   16    { Data record to create the list structure }
  98.   17    PListEntry = ^TListEntry;
  99.   18    TListEntry = record
  100.   19      DirInfo : SearchRec;
  101.   20      Next    : PListEntry;
  102.   21      Previous: PListEntry;
  103.   22    end; {TListEntry}
  104.   23  
  105.   24  var
  106.   25    ListHead : PListEntry;
  107.   26    ListTail : PListEntry;
  108.   27  
  109.   28  
  110.   29  function LowerCase (S : String ) : String;
  111.   30  Var
  112.   31    I : Integer;
  113.   32  begin
  114.   33    for I := 1 to length(s)  do
  115.   34      if ((S[I]>='A') and (S[I]<='Z'))  then
  116.   35        S[I] :=  Chr( Ord( S[I] ) + 32 );
  117.   36    LowerCase := S;
  118.   37  end;
  119.   38  
  120.   39  
  121.   40  
  122.   41  procedure InitDirectoryList;
  123.   42  { Initialize the directory list structure.
  124.   43    For convenience, the first entry contains the default volumne name C:\.
  125.   44  }
  126.   45  begin
  127.   46    ListHead := New(PListEntry);
  128.   47    ListHead^.Next := NIL;
  129.   48    ListHead^.Previous := NIL;
  130.   49    ListTail := ListHead;
  131.   50    ListHead^.DirInfo.Name := 'C:\';
  132.   51  end; {InitDirectoryList}
  133.   52  
  134.   53  
  135.   54  
  136.   55  function  AddEntry (     Location : PListEntry;
  137.   56                       Var ListEntry : SearchRec ) : PListEntry;
  138.   57  Var
  139.   58    NewEntry  : PListEntry;
  140.   59    SavedNext : PListEntry;
  141.   60  
  142.   61  begin
  143.   62    NewEntry := New ( PListEntry );
  144.   63    NewEntry^.DirInfo := ListEntry;
  145.   64  
  146.   65    If  Location = ListTail  Then
  147.   66    {Adding an item on to the tail of the list}
  148.   67    begin
  149.   68      NewEntry^.Next := NIL;
  150.   69      NewEntry^.Previous := ListTail;
  151.   70      ListTail^.Next := NewEntry;
  152.   71      ListTail := NewEntry;
  153.   72    end
  154.   73    else
  155.   74    {inserting an item within the list}
  156.   75    begin
  157.   76      SavedNext := Location^.Next;
  158.   77      Location^.Next := NewEntry;
  159.   78  
  160.   79      NewEntry^.Next := SavedNext;
  161.   80      NewEntry^.Previous := Location;
  162.   81  
  163.   82      SavedNext^.Previous := NewEntry;
  164.   83      
  165.   84    end;{begin}
  166.   85  
  167.   86    AddEntry := NewEntry;
  168.   87  
  169.   88  end;{AddEntry}
  170.   89  
  171.   90  
  172.   91  
  173.   92  function  RemoveEntry ( Location : PListEntry;
  174.   93                          HowMany  : Integer ) : PListEntry;
  175.   94  
  176.   95  { Starting at the point in the list indicated by 'Location', delete
  177.   96    'HomeMany' entries from the list.
  178.   97    Return:  A pointer to the first item after those that were deleted.
  179.   98  }
  180.   99  
  181.  100  var
  182.  101    CountOfItems : Integer;
  183.  102  
  184.  103    function DeleteEntry ( Location : PListEntry ) : PListEntry;
  185.  104    begin
  186.  105      if  Location <> NIL  then
  187.  106      begin
  188.  107        If  Location^.Previous <> NIL  Then
  189.  108          Location^.Previous^.Next := Location^.Next;
  190.  109        If  Location^.Next <> NIL  Then
  191.  110          Location^.Next^.Previous := Location^.Previous;
  192.  111        DeleteEntry := Location^.Next;
  193.  112        If  Location = ListTail  Then
  194.  113          ListTail := Location^.Previous;
  195.  114        Dispose(Location);
  196.  115      end
  197.  116      else
  198.  117        DeleteEntry := NIL;
  199.  118    end;
  200.  119  
  201.  120  begin {RemoveEntry}
  202.  121    For  CountOfItems := 1 to HowMany Do
  203.  122      Location := DeleteEntry ( Location );
  204.  123    RemoveEntry := Location;
  205.  124  end;{RemoveEntry}
  206.  125  
  207.  126  
  208.  127  function Move_Fwd ( Location : PListEntry;
  209.  128                      HowFar : Integer ) : PListEntry;
  210.  129  {Starting from 'location' move ahead 'HowFar' items in the list
  211.  130   and return the new location
  212.  131  }
  213.  132  Var
  214.  133    I : Integer;
  215.  134  begin
  216.  135    For  I := 1 to HowFar  Do
  217.  136      If  Location^.Next <> NIL  Then
  218.  137        Location := Location^.Next;
  219.  138    Move_Fwd := Location;
  220.  139  end;{Move_Fwd}
  221.  140  
  222.  141  
  223.  142  function Move_Bwd ( Location : PListEntry;
  224.  143                      HowFar : Integer ) : PListEntry;
  225.  144  {Starting from 'location' move backwards 'HowFar' items in the list
  226.  145   and return that new location
  227.  146  }
  228.  147  var
  229.  148    I : Integer;
  230.  149  begin
  231.  150    for  I := 1 to  HowFar  do
  232.  151      if  Location^.Previous <> NIL  Then
  233.  152        Location := Location^.Previous;
  234.  153    Move_Bwd := Location;
  235.  154  end;{Move_Bwd}
  236.  155  
  237.  156  
  238.  157  Procedure DisplayFwdList;
  239.  158  Var
  240.  159    TempPtr : PListEntry;
  241.  160  
  242.  161  begin
  243.  162    TempPtr := ListHead;
  244.  163    While  TempPtr <> NIL  do
  245.  164    begin
  246.  165      writeln(TempPtr^.dirinfo.name);
  247.  166      tempptr := TempPtr^.Next;
  248.  167    end;
  249.  168  end;
  250.  169  
  251.  170  procedure DisplayBwdList;
  252.  171  Var
  253.  172    TempPtr : PListEntry;
  254.  173  
  255.  174  begin
  256.  175    TempPtr := ListTail;
  257.  176    while  TempPtr <> NIL  do
  258.  177    begin
  259.  178      writeln (TempPtr^.dirinfo.name);
  260.  179      tempptr := TempPtr^.Previous;
  261.  180    end;
  262.  181  end;
  263.  182  
  264.  183  
  265.  184  
  266.  185  procedure ReadDirectory
  267.  186    ( StartingEntry : PListEntry );
  268.  187  
  269.  188  { Purpose:
  270.  189    Reads the directory contents and inserts
  271.  190    the list into the directory list beginning at 'StartingEntry'.
  272.  191  
  273.  192  }
  274.  193  var
  275.  194    ListEntry : SearchRec;  { Holds the contents of a directory entry
  276.  195                             consisting of filename, size, etc }
  277.  196    CurLocation : PListEntry;
  278.  197    IsADirectory : Boolean;
  279.  198  
  280.  199  begin
  281.  200    {Call FindFirst to locate all files.  The '*.*' matches all filenames,
  282.  201     In this case we want to see ALL files so we use the AnyFile mask.
  283.  202     Note that for the purpose of this example program we are not doing
  284.  203     error checking.  We should check the DosError variable after each
  285.  204     call to FindFirst and FindNext.  Also, its possible that AddEntry
  286.  205     will run of memory and return a NIL value but we aren't checking
  287.  206     for that in this simplified application example.
  288.  207    }
  289.  208  
  290.  209    FindFirst( '*.*', AnyFile, ListEntry );
  291.  210    while  DosError = 0  do
  292.  211    begin
  293.  212      if  ListEntry.Name[1] <> '.'  then
  294.  213        {Add all names other than those beginning with '.'.  This
  295.  214         eliminates our displaying the '.' and '..' names used by DOS}
  296.  215      begin
  297.  216        IsADirectory := (ListEntry.Attr and Directory) = Directory;
  298.  217        if  not  IsADirectory  then
  299.  218          ListEntry.Name := LowerCase (ListEntry.Name);
  300.  219          {We convert file names to lowercase and leave directory names
  301.  220           in upper case for ease of reading the directory listing}
  302.  221        StartingEntry := AddEntry ( StartingEntry, ListEntry );
  303.  222      end; { begin }
  304.  223      FindNext( ListEntry );
  305.  224    end; { begin }
  306.  225  end; { ReadDirectory }
  307.  226  
  308.  227  begin
  309.  228  
  310.  229    InitDirectoryList;
  311.  230  
  312.  231    ReadDirectory ( ListHead );
  313.  232  
  314.  233  
  315.  234    DisplayFwdList;
  316.  235    Readln;
  317.  236  
  318.  237    DisplayBwdList;
  319.  238    Readln;
  320.  239  
  321.  240  end.
  322.  
  323.  
  324. Pointers and the With Statement
  325.      As with the record statement, a pointer to a record structure can use the
  326. with statement to abbreviate the number of identifiers that need to be written.
  327. For example,
  328.  
  329. type
  330.      { Data record to create the list structure }
  331.      PListEntry = ^TListEntry;
  332.      TListEntry = record
  333.        DirInfo : SearchRec;
  334.        Next    : PListEntry;
  335.        Previous: PListEntry;
  336.      end; {TListEntry}
  337. var
  338.      PersonInfo : PListEntry;
  339.      ...
  340.      New ( PersonInfo );
  341.      with PersonInfo^ do
  342.      begin
  343.        DirInfo := DataRecord;
  344.        Next := NextPointer;
  345.      end;
  346.      ...
  347.  
  348. Turbo Pascal Arithmetic Operations
  349.      Pascal provides each of the following data and arithmetic operations:
  350.  
  351.        Basic arithmetic operations: +, -, div, *, /, mod, unary + and -
  352.  
  353.        Relational operations: <, <=, =, >=, >, <>
  354.  
  355.        Logical or bit-level operations:  and, or, xor, not, shl, shr
  356.  
  357.        Boolean operations: and, or, not, xor
  358.  
  359.        String operations
  360.  
  361.  
  362. In addition, through procedures and functions available from the Turbo Pascal
  363. libraries, additional features, including trigonometric, logarithmic, square
  364. root and other functions are available.  These functions are described in
  365. chapter 5, "The System Library Reference", in this freeware book.  Chapter 4
  366. of the Turbo Pascal Reference includes definitions that you can use for
  367. arc-cosine and arc-sine, two popular functions that are, for unknown reasons,
  368. omitted from Borland's System Library.
  369.  
  370.  
  371. Basic Arithmetic Operators
  372.      Constants or variables are combined in arithmetic statements to calculate
  373. new values.  Turbo Pascal's built-in arithmetic operators are:
  374.  
  375.        + Addition:  A + B to compute A plus B.
  376.  
  377.        - Subtraction:  A - B to subtract B from A.
  378.  
  379.        * Multiplication: A * B to multiple A times B.
  380.  
  381.        / Real number division:  A / B to compute A divided by B.
  382.  
  383.        div Truncated integer division:  A div B to compute A divided by B and
  384.        truncated the result towards zero.  For positive results, the truncation
  385.        is towards the next lower integer; for negative results, the truncation
  386.        is towards the next highest integer.  Example:  If the result is 3.7,
  387.        the A div B produces 3.
  388.  
  389.        mod Modulus:  A mod B returns the remainder of the integer division
  390.        between A div B and is equivalent to A - ((A div B) * B).  Example:  10
  391.        mod 3 equals 1.
  392.  
  393.  
  394. When operators are mixed in an expression, such as A+B*C, the algebraic rules
  395. of hierachy apply, and B*C is evaluated first, before adding B.  Turbo Pascal's
  396. expression evaluation ordering is described below in the section titled
  397. Evaluation Hierarchy.
  398.      Note that division is indicated with the div operator for dividing Integer
  399. values, and the / division symbol when dividing Real values. 
  400.  
  401.  
  402. Mixing Data Types in Expressions
  403.      As a general rule, data types should be used consistently in an
  404. expression.  For example, if Ch is of type Char and R is of type Real, it does
  405. not make sense to write Ch * R, and in fact, is not allowed by Turbo Pascal. 
  406. However, it is possible to convert data types from one type to another, both
  407. implicitly and explictly.
  408.      If you mix types in an expression in an unacceptable manner, the Turbo
  409. Pascal compiler will issue an Error 26: Type mismatch error.                   
  410. Many programmer's encounter this error frequently and fortunately, it is not
  411. particularly difficult to fix.  If you see this error message, check your
  412. statements very carefullly, being certain that the data types are correct and
  413. that parentheses are placed in the proper locations.  
  414.  
  415.  
  416. Implicit Type Conversion
  417.      When you multiply a Real value times an Integer value, the result is a
  418. Real value that can be assigned to a real typed variable.  The conversion of
  419. the Integer value to a Real is implicit whenever at least one item in the
  420. expression is a real value.
  421.  
  422.  
  423. Explicit Type Conversion
  424.      You can also explicitly force a real type conversion of the data. 
  425. Converting an integer to a real can be done by adding 0.0 to the integer, since
  426. the result of an arithmetic operation involving an integer and a real value is
  427. a real value.  For instance,
  428.  
  429.      R := (N+0.0) * 4578;
  430.  
  431. You can convert Char values to Integer type values using a type cast, as in
  432. this example which uses the type Integer like a function,
  433.  
  434.      N := Integer(Ch);
  435.  
  436. or by referencing the ordinal function,
  437.  
  438.      N := Ord(Ch);
  439.  
  440. which returns the ASCII code of the character represented by Ch.  To convert an
  441. integer value back to a character, you can write,
  442.  
  443.      Ch := Chr(N);
  444.  
  445. where Chr converts an integer value back to a character type.
  446.      Changing the type of an expression with a type cast is limited to ordinal
  447. data types (Char, Byte, Shortint, Integer, Word, Longint) and to pointer types.
  448. A type rast only works when the internal memory size allocations are identical.
  449. Generally, type casting is used when accessing data that is pointed to by an
  450. untyped  pointer variable.
  451.      To convert a Real value to an Integer, use the Round(R) or Trunc(R)
  452. truncate function.  Round will round its parameter up or down to the nearest
  453. whole number.  Trunc disgards the fractional part and returns the mantissa. 
  454. When converting Real values to Integer, you must insure that the real value
  455. falls within the acceptable range for integers.
  456.  
  457.  
  458. Address-of @ operator
  459.      Turbo Pascal provides a special operator, the @ symbol, to compute the
  460. memory address of a particular object.  For example,
  461.  
  462.      var I : Integer;
  463.        ...
  464.        APointer := @I;
  465.  
  466. assigns the memory location of I to the variable APointer.  This operator is
  467. used often in pointer operations and for passing procedures as parameters to
  468. other procedures and functions.
  469.  
  470.  
  471. Comparision or Relational Operators
  472.      You can test how one variable or constant is related to another by using a
  473. relational operator.  The result of a relational expression is a boolean True
  474. or False. and may be assigned to a Boolean variable, used in if-then statements
  475. for testing a conditional value, and in while and repeat statements.  These
  476. statements are described later.
  477.  
  478.        Equality:  A = B returns True if A and B have the same value, and A and
  479.        B are of any standard type.  Returns False if A is not equal to B.
  480.  
  481.        Less than:  A < B returns True if A is less than B.  In the case of Char
  482.        and String values, the comparison is made according to the underlying
  483.        ASCII code representation of the characters.  Returns False if A is not
  484.        less than B.
  485.  
  486.        Greater than:  A > B returns True if A is greater than B.  Returns False
  487.        if A is not greater than B.
  488.  
  489.        Less than or equal: A <= B returns True if A <= B or A is less than B
  490.        returns False if A is neither equal to B nor less than B.
  491.  
  492.        Greater than or equal:  A >= B returns True if A = B or A is greater
  493.        than B.  Returns False if A is not equal to B nor greater than B.
  494.  
  495.        Not equal:  A <> B returns True if A is not equal to B, and False if
  496.        they are equal.
  497.  
  498.  
  499.       The values represented by A and B may be any valid Turbo Pascal
  500. expression.  You may write, for instance, 
  501.  
  502.      I > (J+10) * 5;
  503.  
  504. Since the result of a relational operator is either True or False, you may
  505. choose to assign this value to a declared Boolean variable, such as the boolean
  506. variable B, as shown here,
  507.  
  508.      B := I > (J+10) * 5;
  509.  
  510.      When comparing values, both operands should be compatible types, with the
  511. exception that if one operand is a Real value,  then it is permissible for the
  512. other operand to be an Integer type expression.  For example,  (I*J) < 45.0;
  513.      The relational operators = and <>. only, may also be used for comparing
  514. pointers to see if they are exactly equal or not equal, respecitvely.  No other
  515. comparisons are allowed directly on pointers (although you can freely compares
  516. the values that the pointers point to).
  517.  
  518.  
  519. Logical or Bit Level Operations
  520.      Logical operations may be applied to any scalar data type (Byte, Smallint,
  521. Integer, Word, Longint)  and perform a bit-wise logical test.  The table below
  522. describes each of the logical operators.  The data type of the result of a bit
  523. wise test is determined by the type of the operands.  
  524.  
  525.           and:  A and B produces a resulting bit pattern that has bits set
  526.        where the corresponding bits in A and in B are both set.  If both
  527.        positions have a 1, then the resulting bit in the same position is a 1. 
  528.        If either position is a zero, then the resulting bit position is also a
  529.        zero.  Example:  If I is an integer having the decimal value 10 (binary
  530.        00001010), then I and 8 (binary 00001010) produces 00001000 since only
  531.        this bit is set in both values.
  532.  
  533.        or:  A or B produces a bit result such that for each bit position in A
  534.        or B this a 1, the resulting bit position is set to 1.  If either of the
  535.        bits in A or B is 1, then the result is also 1.  If both bits are zero,
  536.        then resulting bit is a zero.  Example:  7 or 32 (binary 00000111 or
  537.        binary 0001000) produces 00010111.
  538.  
  539.        not: not A inverts each bit in A.  1 becomes 0 and a zero becomes 1.
  540.  
  541.        xor: A xor B produces the exclusive or of A and B.  xor is like the or
  542.        operation, except that the result of xor is a 1 only when 1 of the
  543.        operands is a 1.  If both operands are 1 or both operands are 0, then
  544.        the result is 0.
  545.  
  546.        shl:  A shl <expression> shifts the bits of A to left the number of bits
  547.        specified by the value of the <expression>.  Example:  0000 0011 shl 3
  548.        produces 0001 1000
  549.  
  550.        shr: A shr <expression> shifts the bits of A to right the number of bits
  551.        specified by the value of the <expression>.  Example:  0101 0010 shr 4
  552.        produces 0000 0101.
  553.  
  554.  
  555. Boolean Operations
  556.      Boolean expressions are written using the following boolean operators:
  557.  
  558.        and:  A and B, where A and B are boolean valued expressions, produces
  559.        True if A and B are both True, and False if either A or B is False.
  560.  
  561.        or:  A or B produces True if either A or B is True, and False only when
  562.        both A and B are False.
  563.  
  564.        not:  not A returns False if A is True, or returns True if A is False.
  565.  
  566.        xor:  A xor B returns True if either A or B is True, but returns False
  567.        if both A and B are True or both A and B are False.
  568.  
  569.  
  570. Boolean operators are frequently used when testing multiple conditions in a
  571. conditional expression, such as an if-then statement.  For example,
  572.  
  573.      if (NumFiles > 10) and (DeleteFiles = 'YES')  then ...
  574.  
  575. evaluates both relational expressions, each of which returns either True or
  576. False, then ands the two boolean values together.  If that result is True, the
  577. then part of the statement is executed.
  578.  
  579.  
  580. Short-Circuit versus Complete Evaluation
  581.      A special feature of Turbo Pascal is the option to use either complete
  582. boolean expression evaluation or short-circuit boolean expression evaluation. 
  583. In complete evaluation mode, the entire boolean expression is evaluated before
  584. testing the result.  In short-circuit mode, Turbo Pascal can optimize the
  585. expression evaluation, often generating less code and on average, executing in
  586. less time.  In the example, 
  587.  
  588.      if (NumFiles > 10) and (DeleteFiles = 'YES')  then ...
  589.  
  590. if short-circuit evaluation is used, Turbo Pascal will jump to the next
  591. statement if NumFiles is less than or equal to 10, since regardless of the
  592. following expression, the overall expression can not possibly be True if the
  593. first operand is already False.  Short-circuit evaluation is especially useful
  594. when checking to see if an array index is within the array bounds and then, in
  595. the same expression, referencing the index value.  For example, in the
  596. statement,
  597.  
  598.      if (Index <= 20) and (DataItem[Index]=0)  then ...
  599.  
  600. short-circuit evaluation ignores the DataItem[Index]=0 relational comparison if
  601. Index is greater than 20.  This is a convenient way to check for an out of
  602. bounds condition.  Without short-circuit evaluation, you would otherwise have
  603. to write this statement as,
  604.  
  605.      if Index <= 20  then
  606.        if DataItem[Index] = 0  then ...
  607.  
  608. to prevent a possible out of bounds array indexing operation to occur.
  609.      Complete evaluation is useful when the expression calls a function which,
  610. in turn, sets some other values elsewhere in the program.  In this instance,
  611. the complete evaluation mode insures that the entire expression is evaluated
  612. fully before making a conditional test.
  613.      The compiler's default operation is to use the short-circuit style of
  614. expression evaluation.  The choice of evaluation methods is made using the $B
  615. compiler directive ($B+ enables complete evaluation, $B- enables short-circuit
  616. evaluation).  See Compiler Directives, later in this chapter.
  617.  
  618.  
  619. String Operations
  620.      The standard data type, String, is a packed array of Char, where the size
  621. of the string is set to 255 by default, plus a length byte, for a total of 256
  622. bytes of memory.  By specifying a new string length in brackets, after String,
  623. a different maximum string length may be specified:  For example,
  624.  
  625.      var
  626.        S1 : String;
  627.        S2 : String[80];
  628.  
  629. S1 defines a default string of length 255; S2 is defined to hold up to a
  630. maximum of 80 characters.   A string variable may, and usually does make use of
  631. fewer bytes than its maximum length, however the allocated memory is always
  632. equal to the maximum length, plus 1.  Turbo Pascal tracks the string's current
  633. length by storing the number of characters in an invisible leading byte at the
  634. beginning of the string.  Since a string is just an array of Char, this puts
  635. the length byte in the zero'th position of the string (for example, S1[0]).
  636.      The normal method of referencing a string's length is to call the Length()
  637. function.  If  S1 contains 'THIS IS A STRING', then Length(S1) returns the
  638. value 16.  If the compiler's range checking option is off {$R-}, you can
  639. directly access the string's length byte, as S1[0], which returns a Char typed
  640. value.  To convert to an integer value, use Ord(S1[0])).  You may also manually
  641. assign a new string length to a string by writing,
  642.  
  643.      S1[0] := Chr( NewLength );
  644.  
  645. Even though referencing a string's length byte violates normal range checking,
  646. in practice it is a common occurrence in Turbo Pascal programs.  And by
  647. default, the Turbo Pascal compiler operates with range checking turned off.
  648.      You may concatenate two strings together (that is, add them together to
  649. make a longer string), using the + symbol.  If S1 contains 'THIS', you could
  650. write,
  651.  
  652.      S1 := S1 + ' IS A TEST!';
  653.  
  654. to assign S1 the new value 'THIS IS A TEST'.  The operand that is added to the
  655. first string may be a string constant, variable, expression or a character Char
  656. type.  The strings are concatenated together up to a maximum of 255 bytes in
  657. length, after which the excess characters are disgarded. 
  658.  
  659.  
  660. Evaluation Hierarchy
  661.      Turbo Pascal expressions can be written with their operands in any order
  662. (such as 3 + 5 * 8).  However, the actual evaluation of the expression does not
  663. occur in the order written.  Instead the expression's result is computed
  664. according to the standard rules of algebraic notation and hierachy.  Elements
  665. of such expressions are evaluated in this order:
  666.  
  667.        The unary not operator has highest precedence,
  668.        Expressions within parantheses are evaluated first,
  669.  
  670.        Then, *, /, div, mod, and the and operator,
  671.  
  672.        Then, the unary + or -
  673.  
  674.        Then, +, -, and the or operator
  675.  
  676.        Lastly, the relational operators =, <, >, <>, <=, >= and the set in
  677.        operator.
  678.  
  679.  
  680. The short-circuit evaluation option (the normal mode of operation) may cause
  681. boolean expressions to terminate their evaluation before the entire expression
  682. is evaluated. 
  683.  
  684.  
  685. Pascal Statements
  686.      Turbo Pascal program statements describe the operations and flow of
  687. execution in the Pascal program.   Each program statement consists of a
  688. sequence of keywords, arithmetic expressions and identifiers, terminated by a
  689. semicolon. The maximum length of a Turbo Pascal line is 126 characters. 
  690. However, in most instances Pascal statements (between semicolons) may be
  691. extended across multiple lines with the only restriction being that character
  692. string constants must not be broken across lines.   If you need to enter a
  693. string constant longer than the maximum 126 character line length allowed by
  694. Turbo Pascal, use the + string concatenation operator and separate the string
  695. into two statements, like this:
  696.  
  697.      S1 := 'This is going to be a really long character string '
  698.        + 'constant that spreads across two lines!';
  699.  
  700.      The Pascal language syntax is often described using a graphic technique
  701. known as syntax diagram or "railroad diagrams" for their resemblence to a
  702. railroad switching yard.  In this format, a Turbo Pascal program statement is
  703. described visually.  An example syntax diagram for the if-then-else statement
  704. is shown in Figure 3.5.
  705.  
  706. ***03tpr05.pcx***
  707. Figure 3.5.  The Pascal syntax diagram for the if-then-else statement.
  708.  
  709.      An alternative notation is to describe this statement as,
  710.  
  711.      if <expression> then <statement>
  712.  
  713. or
  714.  
  715.      if <expression> then <statement> else <statement>
  716.  
  717.      Both notations are used, where appropriate, in Turbo Pascal Reference.
  718.  
  719.  
  720. Program Comments
  721.      Program comments are enclosed within "curly brackets" like this,
  722.  
  723.      { This is a program comment }
  724.  
  725. The contents of a program comment are, with the exception of compiler
  726. directives, ignored by the compiler.  Alternately, you may enclosed comments
  727. using this notation,
  728.  
  729.      (* This is a program comment *)
  730.  
  731. During the process of developing your Turbo Pascal programs, you will find it
  732. convenient to standardize on one or the other comment statement formats.  Most
  733. programmers have gravitated towards use of the curly brackets.  An advantage of
  734. consistently using one or the other type is that while developing and testing
  735. sections of your program, you can comment out entire sections of code,
  736. including sections that already contain comments.  Listing 3.8 shows an example
  737. using the (* and *) notation to temporarily eliminate a section of the program.
  738.  
  739. Listing 3.8.  Example use of the (* and *) to comment out an entire section of
  740. source code.
  741.  
  742. (* COMMENT OUT THIS ENTIRE SECTION
  743.   if  StartEntry <> NIL  then
  744.   begin
  745.      { We still have more path to traverse }
  746.      StartEntry := Move_Fwd( StartEntry, 1);
  747.      if  StartEntry^.Level <= ThisLevel  then
  748.        { this subdirectory isn't open so we can't search any deeper }
  749.        SearchFor := NIL
  750.      else
  751.      if  PathName = ''  then
  752.        { Return the address of the subdirectory entry }
  753.        SearchFor := Move_Bwd( StartEntry, 1 )
  754.      else
  755.        {Continuing searching down the path.  Note that this uses
  756.        a recursive function.}
  757.      SearchFor := SearchFor ( PathName, StartEntry );
  758.   end; {begin }
  759. END OF COMMENTED OUT SECTION *)
  760.  
  761.  
  762. Assignment Statements:  :=
  763. Syntax:
  764.  
  765.      <variable name> := <expression of the appropriate type>;
  766.  
  767. Examples:
  768.      I := 10;
  769.      AllDone := True;
  770.      R := 213456.989;
  771.      J := I * 5 - N;
  772.      OkToPrint := (Answer='Y') and (PrintOption=10);
  773.  
  774. Description:
  775.  
  776.      A variable is given a value with an assignment statement.  Assignment
  777. statements are written as in this example,
  778.  
  779.      R := 1345.78 * I;
  780.  
  781.      The data type of the expression must be compatibile with the data type of
  782. the variable, or using techniques discussed previously, can be explicitly
  783. converted to the appropriate data type.  Assignment statements are also used to
  784. return a function result value, by assigning an expression to the function name
  785. as if it was a variable.  Functions are described later in this chapter.
  786.  
  787.  
  788. Conditional Statements:  If-then-else and case
  789.      Turbo Pascal has two conditional statements, the if-then-else statement
  790. and the case statement.  Both evaluate some condition and execute exactly one
  791. of their possible outcomes selected by the value of the condition.  The
  792. if-then-else statement is typically used for testing amongst a small number of
  793. selections, while the case statement compares one value against a large number
  794. of values or a range of values.
  795.  
  796.  
  797. The if-then and if-then-else statements
  798. Syntax:
  799.      if <expression> then <statement>
  800.  
  801. and
  802.  
  803.      if <expression> then <statement> else <statement>
  804.  
  805. Examples:
  806.      if InputLine = '***END MARKER' then
  807.      begin
  808.        Close(F);
  809.        Close(OutFile);
  810.      end;
  811.  
  812.      if  Cos(Angle)*Theta + DeltaValue > 0.78934  then ...
  813.  
  814.      if  Outlining  then
  815.      begin
  816.        ThrowAway := FindPath ( Item, OutlineNumbers );
  817.        Move( OutlineNumbers[1],
  818.                     StrBuffer[2], Length( OutlineNumbers ));
  819.        Indent := Level*4 + 4;
  820.      end
  821.      else
  822.        Indent := Indent + 2;
  823.  
  824. Description:
  825.  
  826.      <expression> is any expression returning a boolean True or False value,
  827. ranging from a simple Boolean to a complex relational expression.  If the
  828. expression is True, the statement following then is executed next, while if the
  829. expression is False, the then part is ignored.  For example,
  830.  
  831.      if  AllDone  then
  832.        Close( InputFile );
  833.  
  834. In this statement, if AllDone is True, then the InputFile is closed.  If
  835. AllDone is False, then the InputFile is left open and the Close statement is
  836. not executed.
  837.      <statement> may be any Pascal statement, including a group of statements
  838. nestled between begin and end.
  839.      In the if-then-else form, if the expression is True, the then part is
  840. executed, but if False, the else part is executed.   if-then and if-then-else
  841. statements are often spread across multiple lines to improve readability.  For
  842. example,
  843.  
  844.      if (Index <= MAXENTRIES) then
  845.        XArray[Index] := DataItem
  846.      else
  847.        Writeln('The list is now full and cannot hold more entries');
  848.  
  849. The <statement> part of an if-then or if-then-else may itself contain
  850. additional if statements.  For example,
  851.  
  852.      if condition1 then
  853.        if condition2  then
  854.           <statement>
  855.        else
  856.           <statement>
  857.  
  858. When if-then-else statements are nested like this, the else binds together with
  859. the most recent if-then.  To use a different ordering, you may optionally
  860. enclose the statement within begin-end, like this:
  861.      
  862.      if condition1 then
  863.      begin
  864.        if condition2  then
  865.           <statement>
  866.      end
  867.      else
  868.        <statement>
  869.  
  870.  
  871. The case Statement
  872. Syntax:
  873.      case <expression> of
  874.        <constant> : <statement>;
  875.        <constant> : <statement>;
  876.        <constant> : <statement>;
  877.        ...
  878.      else
  879.        <statement>
  880.      end;
  881.  
  882. The else part is optional.  <constant> may specify a range of values using ".."
  883. notation, as for example, "1..10" to specify values in the range of 1 to 10.
  884.  
  885. Examples of case statements:
  886.      case EnteredChar of
  887.        'a'..'z' : EnteredChar := Chr( Ord(EnterChar) - 32 ); { convert to lower
  888. case }
  889.        'X' : DoExitCommand;
  890.        'O' : DoOpenFile;
  891.        else
  892.           writeln('Command entered is not recognized.');
  893.      end;
  894.  
  895.      case Index of
  896.        -32768..0:   Writeln('Must use a positive valued index.');
  897.        1..10 :      DoIndexProcessing (Index);
  898.        11..15:      DoSpecialOperation (Index);
  899.        16..32767:   Writeln('Index must be between 1 to 15.');
  900.      end;
  901.  
  902. Description:
  903.      The case statement contains an initial expression called the selector,
  904. which is used to choose from among a list of various outcomes.  When the
  905. selector matches an item in the list, the corresponding statement is executed. 
  906. Only one match per case statement is permitted.
  907.      The selector <expression> is any expression evaluating to a simple byte or
  908. word-sized result, such as an integer, word or char data type.  
  909.      The <constant> value should correspond to the type of the selector
  910. expression and may be either a single value or a range of values.  A value
  911. range is written as,
  912.  
  913.      100..199:
  914.  
  915. where .. is placed between the start and end values for the range.
  916.      Each <statement> may be any Turbo Pascal statement including a group of
  917. statements nested inside begin and end.
  918.      The else part of a case statement is optional, and specifies what to do in
  919. the event that no value in the case list matches the selector.  If there is no
  920. match in the case list and there is no else part, then no statements are
  921. executed.
  922.  
  923.  
  924.  
  925.  
  926. Looping Statements:  For, While and Repeat
  927.  
  928.      Looping statements provide a mechanism for repeatedly executing
  929. one or more program statements. Turbo Pascal provides 3 looping
  930. constructs: the for loop, the while loop and the repeat-until loop.
  931.  
  932.  
  933. The for loop
  934. Syntax:
  935.     for <control variable> := 
  936.         <starting expression> to <ending expression> do                <statement>
  937.  
  938. and
  939.  
  940.     for <control variable> :=
  941.         <starting expression> downto <ending expression> do
  942.             <statement>
  943.  
  944. Examples:
  945.     for I := 1 to 10 do
  946.         Writeln('Count = ', I);
  947.  
  948.     { Prints the alphabet from A to Z }
  949.     For Ch := 'A' to 'Z' do Write(Ch);
  950.  
  951.     { Convert string S to lower case letters }
  952.     for I := 1 to length(S)  do
  953.         if ((S[I]>='A') and (S[I]<='Z'))  then
  954.             S[I] :=  Chr( Ord( S[I] ) + 32 );
  955.  
  956. Description:
  957.       The for loop repeatedly executes a sequence of
  958. statements while incrementing or decrementing a loop control variable
  959. during each repetition. ntrol variable> must be a simple ordinal type
  960. (Byte, Char, Smallint, Integer, Word or Longint) variable (not an
  961. array element, record field or real typed) defined locally to a
  962. procedure or function, or a global value only for loops located in the
  963. main body of the program. The control variable is given an initial
  964. value specified by <starting expression>.
  965.  
  966.      If the control variable is within the range specified by the
  967. <starting expression> and the <ending expression>, then the
  968. <statement> part is executed. The <statement> part may include a group
  969. of statements between begin and end. he statements have executed, the
  970. control variable is incremented (or decremented in the case of the
  971. downto). If the new value of the control variable is still within the
  972. range of the starting and ending expression, the loop is executed
  973. again. On ce the control variable falls outside the range of the
  974. starting and ending expressions, program control resumes at the point
  975. immediately after the for statement. the loop, the control variable
  976. should be treated as read only meaning that you must not assign a new
  977. value to the control variable. While the compiler allows you to assign
  978. a new value, the result of this operation is undefined and should not
  979. be u sed. Similarly, the value of the control variable is undefined
  980. after the loop has completed and it should not be relied upon in any
  981. future expressions or conditional expressions. However, if a goto
  982. statement (see below) transfers control out of the for loop you may
  983. then reference the control variable outside the scope of the loop.
  984.  
  985.  
  986.  
  987. While Loop
  988. Syntax:
  989.  
  990.      while <expression> do <statement>
  991.  
  992. Examples:
  993.      while not Eof(InputFile)  do
  994.      begin
  995.           Readln(InputFile, InputLine);
  996.           SaveLine(InputLine);
  997.      end;
  998.           
  999.      while (I>1)  and (S[I-1] <> ' ')  do
  1000.      begin
  1001.           Insert (',', S, I);
  1002.           I := I - 3;
  1003.      end;
  1004.  
  1005. Description:
  1006.      The while loop repeatedly executes a statement or group of statements as
  1007. long the control expression is True.   The control expression must always
  1008. return a boolean True or False value.  As soon as the expression is False, the
  1009. loop terminates and the program resumes execution at the statement after the
  1010. while loop.
  1011.      The while loop always evaluates the expression at the beginning of the
  1012. loop.  (See also the repeat-until loop for a loop that evaluates the expression
  1013. at the end of the loop.)
  1014.  
  1015. Repeat Loop
  1016.  
  1017. Syntax:
  1018.      repeat    <statement> until <expression>
  1019.  
  1020. Examples:
  1021.      I := 0;
  1022.      repeat
  1023.           I := I + 1;
  1024.           Writeln(I);
  1025.           I := I + 1;
  1026.      until I = 10;
  1027.  
  1028.      { Keep reading keyboard commands until user selects a Done
  1029.        function }
  1030.      MenusDone := False;
  1031.      repeat
  1032.        MenuCommand := GetKey;
  1033.        Command := MenuCommand;  {Set up default value for
  1034.                                         return'd command}
  1035.        case  MenuCommand  of
  1036.           KEY_LEFTARROW:
  1037.           begin
  1038.             ...     
  1039.           end; { begin }
  1040.           ...
  1041.           KEY_ENTER:
  1042.             begin
  1043.             MenuPtr := FindItem(CurrentMenu, MenuIndex);
  1044.             Command := MenuPtr^.CmdCode;
  1045.             MenusDone := True;
  1046.           end; { begin }
  1047.           KEY_ESCAPE:        MenusDone := TRUE;
  1048.           else begin  {all other keys} end;
  1049.        End; { case }
  1050.      Until  MenusDone;
  1051.  
  1052. Description:
  1053.      repeat-until repetitively executes one or more statements appearing
  1054. between the repeat and the until keywords.  The statements are executed as long
  1055. as the conditional expression after the until is False.  When the condition
  1056. evaluates to True, the loop terminates and program execution resumes at the
  1057. statement following until.
  1058.      The repeat-until statement always executes the loop at least once since
  1059. the conditional test is not performed until reaching the until statement.
  1060.      Unlike the other looping statements, the repeat and until keywords suffice
  1061. to delineate multiple statements, hence, you do not need to enclose multiple
  1062. statements with begin-end.
  1063.  
  1064.  
  1065. Labels and Goto
  1066. Goto Syntax:
  1067.      goto <label>
  1068.  
  1069. Example goto:
  1070.      goto 100;
  1071.  
  1072. Label declaration Syntax:
  1073.      label <list of labels>
  1074.  
  1075. Example Label declaration:
  1076.      label 100, 200, 300;
  1077.  
  1078. Label usage Syntax:
  1079.      <label>:
  1080.  
  1081. Example label usage:
  1082.      100:
  1083.  
  1084. Example use of Label and Goto:
  1085.      procedure LabelDemo;
  1086.      label  999;
  1087.      var    I : Integer;
  1088.      begin
  1089.        for I := 1 to MAXLINES do
  1090.        begin
  1091.           Writeln(Outfile, Lines[I] );
  1092.           if IoResult <>  0 then
  1093.           begin
  1094.             Writeln('Error occurred while writing output
  1095.                               file.');
  1096.             goto 999;
  1097.           end;
  1098.        end;
  1099.      999: Close(OutFile);
  1100.      end;
  1101.  
  1102. Description:
  1103.      The goto statement transfers program execution directly to some other
  1104. location in the program specified by a label, where <label> is an unsigned
  1105. integer up to 4 digits in length and is located somewhere within the program or
  1106. program unit.  Each label must be explicitly declared in a label declarations
  1107. section at the beginning of the program, unit, procedure or function, just like
  1108. any other identifier.  The actual location of the label is determined by
  1109. placing the label, followed by a colon, somewhere within the program text.
  1110.      A label and a goto statement are sometimes used within procedures to
  1111. quickly transfer program execution to the end of the procedure.  An error
  1112. condition or a user input request to finish up might prompt an early completion
  1113. to execution of a sequence of statements.  The example label, shown as "999" in
  1114. the example above, must be declared before use with the label statement, and
  1115. then is positioned within the program text by writing "999:" at the beginning
  1116. of a statement.  The label is referenced by the goto 999 statement.
  1117.  
  1118. Important note:  Do not use Goto to jump into a lower level block
  1119.      Do not use goto and a label to jump into the middle of a looping
  1120. construct, such as,
  1121.  
  1122.      for I := 1 to 30 do
  1123.      begin
  1124.        1: {Don't jump to the middle of a loop}
  1125.        ...
  1126.      end;
  1127.  
  1128.      The compiler will not generate an error if you compile such code, however,
  1129. the result is potentially random.  Never jump into a deeper nesting level, only
  1130. to the same level or to a higher level.
  1131.      The label and the goto statement that refers to it, should always be in
  1132. the same program block.  That means you can not use goto to jump from within
  1133. one procedure or function into another procedure or function.
  1134.      Lastly, do not place a label directly after a then statement, such as,
  1135.  
  1136.        if I = 10 then 1: ...
  1137.  
  1138. although you may place a label within a begin-end block that follows a then
  1139. statement.
  1140.  
  1141.  
  1142. Procedures and Functions
  1143.      Few Pascal programs consist of a single main program body.  Most are split
  1144. into subtasks or subroutines, called procedures (or their close cousin, the
  1145. function).  The use of procedures and functions is an essential part of Turbo
  1146. Pascal programming, and through appropriate use of procedures you can use
  1147. structured program techniques to create modular programs that are more reliable
  1148. and  easier to maintain.  
  1149.      Procedures provide a method of isolating portions of your program into
  1150. separate, callable routines, which you can call or activate from anywhere
  1151. within your program.  Procedures may have a list of parameters, which are used
  1152. to pass values into the procedure, and to return results.
  1153.      Functions are like procedures, except that a function is called from
  1154. within an expression and directly returns a result to be used in evaluating the
  1155. expression.
  1156.      Turbo Pascal provides enhancements to the basic Pascal procedure to
  1157. provide for support of the underlying 80x86 microprocessor, and the creation of
  1158. Pascal language interrupt handlers and assembly language interfacing.  These
  1159. features are specified with the keywords, near, far, and interrupt.  Assembly
  1160. language statements are incorporated directly into the Pascal source using
  1161. either the asm or inline facilities.
  1162.  
  1163. Procedures
  1164. Syntax:
  1165.      procedure <identifier> <optional parameter list> <procedure body>
  1166.  
  1167.      The <optional parameter list> defines the values and data types that may
  1168. be passed to the procedure at the time the procedure is called, and if the
  1169. procedure may return values to the caller.  Parameter lists are described in
  1170. more detail, below.
  1171.      The <procedure body>  normally consists of a paired begin-end statement,
  1172. enclosing zero or more program statements.  In Turbo Pascal, the <procedure
  1173. body> may be optionally prefaced with:
  1174.  
  1175. near;       Use the 80x86 near procedure calling convention.
  1176.  
  1177. far;        Use the 80x86 far calling convention.
  1178.  
  1179. interrupt;  For creating special interrupt handler procedures.
  1180.  
  1181. library;    To create a dynamic link library procedure.  See
  1182.             Chapter 2, "Units and Dynamic Link Libraries" in
  1183.             the Borland Pascal Developer's Guide, Que, 1992.
  1184.  
  1185. Instead of the normal begin-end statement block, you may write: 
  1186.  
  1187.      forward; 
  1188.  
  1189. to specify that the procedure body  is specified later in the
  1190. program.
  1191.  
  1192.      Use external when the procedure body is defined in a separately compiled
  1193. object module that has been written in assembly language.
  1194.  
  1195.      Use inline() to incorporates machine code directly into the compiled code,
  1196. rather than generating a call to the procedure.  See Chapter 6, "Assembly
  1197. Language Programming" in the Borland Pascal Developer's Guide.
  1198.  
  1199.  
  1200. The <Optional parameter list>
  1201.      Parameters to a procedure or function are specified within parentheses,
  1202. after the procedure or function identifier.  The parameter list specifies one
  1203. or more parameters, their type, and if the parameter is passed by value (a
  1204. value parameter) or by reference (a variable parameter).  When defining the
  1205. parameter list, you create a list of variables (similar to a var declaration)
  1206. assigning an identifier and data type to each parameter, and specifying whether
  1207. the parameter is a value parameter or a variable parameter.  For example,
  1208.  
  1209.      procedure PrintSum (A, B : Integer);
  1210.      begin
  1211.        Writeln('Sum of ',A,' + ',B, ' = ',A + B);
  1212.      end;
  1213.  
  1214. defines a procedure PrintSum having two integer parameters A and B, both passed
  1215. by value.  The parameters A and B become local variables to the procedure
  1216. PrintSum, and are undefined outside the scope of the procedure.
  1217.      To use this procedure, you call the procedure by placing the procedure
  1218. name and the values for the parameters in a statement, like this:
  1219.      begin
  1220.      PrintSum( 10, 20 );
  1221.  
  1222. which results in this output:
  1223.  
  1224.      Sum of 10 + 20 = 30
  1225.  
  1226. The first parameter value, 10, is assigned to the parameter variable A, and the
  1227. second parameter value, 20, is assigned to the parameter variable B.  In the
  1228. case of value parameters such as A and B, you can use any expression, which
  1229. will be evaluated during program execution at the time of the procedure call. 
  1230. For example,
  1231.  
  1232.      PrintSum( 10+30, 5*TotalSize );
  1233.  
  1234. The expression 10+30 will evaluate to 40, and A will get the value of 40.  
  1235.      Variable parameters provide a way for the procedure to modify the contents
  1236. of a variable passed to it.  For example, by redefining PrintSum as shown
  1237. below, the variable C becomes a var variable parameter.  Inside PrintSum, C is
  1238. assigned the result of A+B.  
  1239.  
  1240.      procedure PrintSum( A, B: Integer; var C: Integer);
  1241.      begin
  1242.        Writeln('Sum of ',A,' + ',B, ' = ',A + B);
  1243.        C := A + B;
  1244.      end;
  1245.  
  1246. In this way, when PrintSum is called like this,
  1247.  
  1248.      PrintSum( 10+30, 40, AValue );
  1249.  
  1250. the local variable C gets assigned the sum, 80.  The variable passed as a
  1251. parameter to PrintSum, AValue, also gets assigned the sum, 80.  A parameter
  1252. defined as a var type, can only have a matching variable passed to it as a
  1253. parameter, so that it can return a value.  You must not try to pass an
  1254. expression to a matching variable parameter, only to a value parameter.
  1255.  
  1256.  
  1257. Arrays as Parameters
  1258.      Arrays and array elements may be passed to procedures as value parameters
  1259. or as variable parameters.
  1260.      To pass an individual array element requires only that the parameter
  1261. expression match the data type of the defined value parameter.  For example,
  1262.  
  1263.      var
  1264.        AnArray : Array[1..10] of Integer;
  1265.  
  1266.      procedure P ( X : Integer );
  1267.      begin
  1268.        ...
  1269.      end;
  1270.      ...
  1271.      P ( AnArray[5] );
  1272.  
  1273. Array elements may also be passed as variable parameters.  For example,
  1274.  
  1275.      procedure P ( var X : Integer );
  1276.      begin
  1277.        ...
  1278.      end;
  1279.      ...
  1280.      P ( AnArray[5] );
  1281.  
  1282.      To pass an entire array to a procedure or function parameter requires that
  1283. a user defined type be declared to describe the array.  For example, 
  1284.  
  1285.      type
  1286.        TArray : Array[1..10] of Integer;
  1287.      var
  1288.        AnArray : TArray;
  1289.  
  1290.      procedure P ( X : TArray );
  1291.      begin
  1292.        ...
  1293.      end;
  1294.      ...
  1295.      P ( AnArray );
  1296.  
  1297. Turbo Pascal requires the parameter's type to be a simple identifier, so you
  1298. cannot write:
  1299.  
  1300.      procedure P ( X : Array[1..10] of Integer );
  1301.  
  1302. Instead, you must always define a new type equivalent to the array definition,
  1303. and use that to declare array parameters.
  1304.      The example above passes an array by value.  Internally, this is
  1305. implemented by copying the entire array onto the stack, and then call the
  1306. procedure.  Not surprisingly, for large arrays this is both a time and memory
  1307. consumer.  Instead, for large structures, such as arrays or large records, it
  1308. is recommend that you pass arrays as var parameter types, like this:
  1309.  
  1310.      procedure P ( var X : TArray );
  1311.  
  1312.  
  1313. Strings as Parameters
  1314.      Strings may be passed either by value or as variable parameters.  When a
  1315. string is passed to a procedure parameter by value, any string expression may
  1316. be used at the point of call.  The compiler will generate code to evaluate the
  1317. expression and then make a copy of the result, which is then passed to the
  1318. procedure.  In some instances, this extra overhead of making a copy of the
  1319. string value may be prohibitive.  Instead, you may wish to pass the string as a
  1320. variable parameter since the compiler will then reference the original string,
  1321. rather than making a copy of the string.  For example,
  1322.  
  1323.      Procedure StringDemo( var S : String );
  1324.      begin
  1325.        S := '/' + S + '/';
  1326.      end;
  1327.  
  1328. which is then called with,
  1329.  
  1330.      var  AString : String;
  1331.      ...
  1332.      AString := 'TOOLS';
  1333.      StringDemo( AString );
  1334.  
  1335. results in AString getting the value, '/TOOLS/'.  When using a variable
  1336. parameter, you must always pass a variable identifier when the procedure is
  1337. called.  Using a string expression, such as,
  1338.  
  1339.      StringDemo('TOOLS');
  1340.  
  1341. will result in a compiler error message.  Keep in mind that any changes you
  1342. make to the parameter variable within the procedure will be reflected in the
  1343. string that was passed to the procedure.  
  1344.  
  1345. Important Note:  Mixing String Types and Var Parameters
  1346.      Normally Turbo Pascal will permit mixing of different string types when
  1347. they passed as variable parameters.  For instance, if AString is defined as,
  1348.  
  1349.      var  AString : String[30];
  1350.  
  1351. then,
  1352.  
  1353.      StringDemo( AString );
  1354.  
  1355. will result in an error because the parameter variable S is defined as type
  1356. String, which is equivalent to String[255].  Normally, Turbo Pascal performs
  1357. "strict type checking" on parameter strings.  This means that the string type
  1358. and length must be identical.  However, you can disable strict type checking
  1359. for var-parameter strings, by using the {$V-} directive to disable
  1360. var-parameter string type checking.  With {$V-} in effect, Turbo Pascal will
  1361. allow you to mix different length strings for var-string parameters.  You must
  1362. insure that you do not inadvertently access portions of the string parameter
  1363. that are out of bounds.  See "Compiler Directives" later in this chapter for
  1364. more information about the $V directive.
  1365.      Another standard method of passing strings as var parameters is to create
  1366. a user defined type and then to use that type consistently for string
  1367. variables.  For instance,
  1368.  
  1369.      type
  1370.        String80 = String[80];
  1371.      var
  1372.        AString : String80;
  1373.      procedure P ( var StringParam : String80 );
  1374.      begin
  1375.        ...
  1376.      end;
  1377.  
  1378. Now, when the statement P( AString) is executed, AString has exactly the same
  1379. type P's StringParam parameter.
  1380.  
  1381.  
  1382. Records as Parameters
  1383.      To pass a record structure as either a value or variable parameter
  1384. requires that you create a user defined data type equivalent to the record's
  1385. definition.  Example:
  1386.  
  1387.      type
  1388.        TPersonInfo = record
  1389.           Name : String[30];
  1390.           Phone : String[14];
  1391.           Age : Integer;
  1392.        end;
  1393.      var
  1394.        PersonInfo : TPersonInfo;
  1395.      
  1396.      procedure P ( PersonRecord : TPersonInfo );
  1397.      begin
  1398.        ...
  1399.      end;
  1400.      ...
  1401.      P ( PersonInfo );
  1402.  
  1403.  
  1404. Summary of Using Parameter Values and Variables
  1405.      To summarize, parameter variables define a list of local variables to the
  1406. procedure, each of which is matched to a parameter value at the time the
  1407. procedure is invoked.  Parameter variables may be either value parameters or
  1408. variable parameters.  A value parameter may receive any expression, which will
  1409. be evaluated at the time of the procedure call.  A variable parameter must only
  1410. receive another variable as its parameter, and may be used by a procedure to
  1411. return a value to the procedure's caller.
  1412.      Structured data types must make use of a user defined type to specify the
  1413. parameter's data type.
  1414.  
  1415.  
  1416. The Procedure Body
  1417. Syntax:
  1418.      <optional variable declarations>
  1419.      <optional procedure declarations>
  1420.      begin
  1421.        statements;
  1422.      end;
  1423.  
  1424. Example:
  1425. Listing 3.8.  The DrawWindow procedure.
  1426.  
  1427. Procedure DrawWindow (X1, Y1, X2, Y2 : Integer );
  1428. { Draws a window for a menu or dialog.  Essentially this declares
  1429. a text viewport using the Turbo Window procedure and proceeds to
  1430. draw a border "around" the window.  In this case, the border
  1431. occupies one character on all sides of the requested area.}
  1432. Var
  1433.   Width : Integer;
  1434.   S : String[80];
  1435.   Y : Integer;
  1436.  
  1437. Begin
  1438.   {Create Window area on the screen}
  1439.   Window (X1, Y1, X2, Y2+1);
  1440.   Width := X2-X1+1;
  1441.  
  1442.   {Draw border around the window}
  1443.   {First draw the top line across the window border}
  1444.   FillChar ( S, Width, Chr(196) );
  1445.   S[0] := Chr(Width);
  1446.   S[1] := Chr(218);
  1447.   S[Width] := Chr(191);
  1448.   WriteStr( 1, 1, S, LightGray, Black );
  1449.  
  1450.   {Next, Draw the sides of the window border}
  1451.   FillChar ( S, Width, ' ' );
  1452.   S[0] := Chr(Width);
  1453.   S[1] := Chr(179);
  1454.   S[Width] := Chr(179);
  1455.   For Y := 2 To Y2-Y1  Do
  1456.      WriteStr(1, Y, S, LightGray, Black );
  1457.  
  1458.   {Then Draw the bottom border}
  1459.   FillChar ( S, Width, Chr(196) );
  1460.   S[0] := Chr(Width);
  1461.   S[1] := Chr(192);
  1462.   S[Width] := Chr(217);
  1463.   WriteStr( 1, Y2-Y1+1, S, LightGray, Black);
  1464. End;
  1465.  
  1466. Description:
  1467.      The body of a procedure may contain additional identifier declarations,
  1468. including local procedures and functions that are defined inside the procedure
  1469. or function.  Such identifiers, including sub-procedures or functions, are
  1470. available for use solely within the scope of the outer procedure.
  1471.      The main body of the procedure consists of the keyword begin, followed by
  1472. zero or more Pascal statements, and terminated by the keyword end.  Listing 3.8
  1473. presents a sample procedure DrawWindow, which displays a rectangular window on
  1474. the screen, complete with a border.  DrawWindow has 4 parameter variables, X1,
  1475. Y1, and X2,Y2 which are integer values describing the screen coordinates of the
  1476. upper left and lower right corner of the window.  DrawWindow also has 3 local
  1477. variables, Width, S, and Y.  Both the parameters and the local variables are
  1478. all local to procedure DrawWindow meaning that they are not defined nor
  1479. available outside the procedure.
  1480.  
  1481.  
  1482. Forward declared procedures
  1483.  
  1484. Syntax:
  1485.      procedure <identifier> <parameter list>; forward;
  1486.      ...
  1487.      procedure <identifier>; <procedure body> 
  1488.        or external or asm keywords.
  1489.  
  1490. Example:
  1491.      The following is an illustration of a forward declared procedure named
  1492. DoCommand.  DoCommand is declared as forward because it must be called by the
  1493. DoStatement procedure; however, DoCommand may also need to call DoStatement so
  1494. it would not be possible to define either before the other except to make one a
  1495. forward declared procedure.
  1496.  
  1497. Listing 3.9.  The use of forward declared procedures.
  1498.  
  1499. procedure DoCommand ( TheCommand : Word ); forward;
  1500.  
  1501. procedure DoStatement ( Location : Integer );
  1502. begin
  1503.   ...
  1504.   if  InputLine[Location]= '.'  then
  1505.      DoCommand ( HitPeriod );
  1506. end;
  1507.  
  1508. procedure DoCommand;
  1509. begin
  1510.   case TheCommand of
  1511.      OnStatement :  DoStatement ( Location );
  1512.      HitPeriod      :         DoPeriod;
  1513.      ...
  1514.   end;
  1515. end;
  1516.  
  1517. Description:
  1518.      At times, a procedure identifier needs to be declared early in a program
  1519. so that subsequently defined procedures can call it.  However, since this
  1520. procedure, in turn, needs to call other procedures that have not yet been
  1521. defined, the main body of the procedure must be defined after the declaration
  1522. of those procedures that it needs to use.  Such a procedure is declared using
  1523. the forward declaration instead of a procedure block.  The actual
  1524. implementation then appears later in the program or unit.
  1525.      The actual definition that appears later is not allowed to be another
  1526. forward declaration, nor a near, far or inline declaration.  However, it may
  1527. contain the external or asm assembly language directives.  Further, at the
  1528. point that the forward declared procedure is actually implemented, it should
  1529. not redefine the parameter list.
  1530.      In between the procedure's forward declared header and the subsequent
  1531. procedure definition, other procedures and functions may be defined.  In this
  1532. way, procedures can be written that call each other as shown in Listing 3.9,
  1533. above.
  1534.  
  1535.  
  1536. Near and Far procedure call models
  1537. Example:
  1538.      Example of a procedure declared using the far declaration.  This example
  1539. uses the Turbo Vision TCollection feature ForEach, which requires a pointer to
  1540. a far procedure as a parameter, shown in the PhoneBook^.ForEach( @PrintEntry )
  1541. statement.
  1542.  
  1543.      procedure PrintEntry( OneEntry : PPersonInfo ); far;
  1544.      begin
  1545.        with  OneEntry^  do
  1546.           Writeln(Name,Address,City,State,Zip,Age);
  1547.      end; { PrintEntry }
  1548.  
  1549.      begin
  1550.        PhoneBook^.ForEach( @PrintEntry );
  1551.      end;
  1552.  
  1553. Description:
  1554.      The 80x86 CPU architecture divides memory in to 64k byte chunks called
  1555. segments.  Procedures may be called within a segment or across segment
  1556. boundaries.  When a procedure call is made within a segment, it is a near
  1557. procedure call.  When a procedure call is made across segment boundaries, it is
  1558. a far procedure call.
  1559.      A near procedure call requires fewer machine instructions, hence it
  1560. requires less memory and executes slightly faster than a far call.  However,
  1561. near procedures can only be called from within the same module (or unit) that
  1562. they are defined, while a far defined procedure can be called from any code
  1563. module.
  1564.      Turbo Pascal automatically determines if a procedure or function should
  1565. use the near or far call memory model.  Normally, all procedures or functions
  1566. declared in the Interface section of a program unit are far declared.  All
  1567. procedures or functions defined within the program or implementation section of
  1568. a unit are near model calls.
  1569.      Using the near or far declarations, you can override the automatically
  1570. determined procedure call type.   Some examples of procedure or functions that
  1571. you might override are:
  1572.  
  1573.        Procedures or functions which are themselves passed as variable
  1574.        parameters must be declared as far procedures.
  1575.  
  1576.        Overlay procedures (those that are swappable out of memory) must be far
  1577.        procedures.
  1578.  
  1579. In addition to using the far directive, you can force the compiler to generate
  1580. far calls for all procedures and functions by using the {$F+} compiler
  1581. directive.  The normal state is {$F-}, meaning that the compiler will
  1582. automatically choose either near or far as appropriate.  In the {$F+} state,
  1583. the compiler will always generate far calls.
  1584.  
  1585.  
  1586. Interrupt Procedures
  1587.      Interrupt declarations specify that the procedure is an interrupt handler
  1588. procedure.  Interrupt handlers in Turbo Pascal are fully explained in Chapter
  1589. 11.  The basic interrupt procedure must follow this format:
  1590.  
  1591. procedure Handler
  1592.   (Flags, CS, IP, AX, BX, CX, DX, SI, DI, DS, ES, BP : Word);
  1593. interrupt;
  1594. begin
  1595.      ...
  1596. end;
  1597.  
  1598.      The procedure header must be specified as shown, so that all of the CPU
  1599. registers may be accessed as if they were parameter variables (even though the
  1600. var keyword is not specified).
  1601.      Interrupt procedures should be activated only by an interrupt condition
  1602. and cannot be called from within your Turbo Pascal program as if they were a
  1603. normal procedure.  Chapter 11 provides additional details and examples of
  1604. interrupt procedures.
  1605.  
  1606.  
  1607. Assembly language procedures:  External, Inline and Asm
  1608.      Turbo Pascal provides 3 types of assembly language interfacing.  
  1609.        Assembly language routines can be written and assembled using an
  1610.        external assembler such as Turbo Assembler, and then linked to your
  1611.        Turbo Pascal programs.  Such routines are made visible to the Turbo
  1612.        Pascal code by defining a corresponding procedure or function header
  1613.        within your Turbo Pascal source and declaring it as external.  The
  1614.        external assembly language routine is then linked from the assembled
  1615.        object module.
  1616.        Turbo Pascal contains a built-in assembler that let's you write complete
  1617.        assembly language routines without leaving the Turbo Pascal compiler. 
  1618.        Such routines are written using the asm keyword.
  1619.        Lastly, you can embed values, such as machine code or data values
  1620.        directly into the generated code using the inline statement.
  1621. Turbo Pascal's built-in assembly language features and the Turbo Assembler are
  1622. described in Chapter 6, "Assembly Language Programming" in the Borland Pascal
  1623. Developer's Guide, Que Books, 1992.
  1624.  
  1625.